#!/bin/bash
# *************************************
# 功能: 自动配置当前项目的基础属性信息
#       基于角色修改特定目录下的文件
# 作者: 王树森
# 联系: wangshusen@sswang.com
# 微信群: 自学自讲—软件工程
# 抖音号: sswang_yys 
# 版本: v0.1
# 日期: 2024-07-24
# *************************************

# 获取基础目录信息
local_config_file="${tmpl_dir}/config"
local_hosts_file="${tmpl_dir}/hosts"
target_config_file="${conf_dir}/config"
target_hosts_file="${conf_dir}/hosts"

# 基于角色确定要使用的config文件
if [ "${user_role}" == "develop" ]; then
  config_file="${target_config_file}"
  _hosts_file="${target_hosts_file}"
  old_config_file="${local_config_file}"
else
  config_file="${local_config_file}"
  _hosts_file="${local_hosts_file}"
  old_config_file="${target_config_file}"
fi

# 定制格式化信息显示数组
array_context=(集群版本 集群模式 部署方式 容器引擎 网段信息 仓库协议 网络方案 网络模式)
array_key=(k8s_version cluster_type default_deploy_type default_container_engine_type target_net harbor_http_type default_network_type default_network_proxy)
array_remark=(
             "1.6+"
             "alone|multi"
             "online|offline"
             "docker|containerd|cri-o"
             "10.0.0"
             "http|https"
             "flannel|calico|cilium"
             "iptables|ipvs"
             )


# 提取配置属性值相关信息函数
get_config_attr_value(){
  # 接收参数
  local attr_key="$1"
  local file="$2"

  # 从指定配置文件中提取对应的属性值
  grep "^${attr_key}=" "${file}" | awk -F'"' '{print $2}'
}

# 定制属性修改的内容临时保存数组
declare -a array_key
declare -A array_edit
array_kv=""
for i in $(seq ${#array_key[@]}); do
  value=$(get_config_attr_value "${array_key[$i-1]}" "${config_file}")
  array_kv="${array_kv} [${array_key[$i-1]}]=${value}"
done
array_define="declare -A array_edit=(${array_kv})"
eval "${array_define}"

# 获取主机角色信息
get_hosts_role(){
  # 接收参数
  local hostname="$1"

  # 判断逻辑
  if [[ "${hostname}" =~ .*node.* ]]; then
    local hostrole="node"
  elif [[ "${hostname}" =~ .*master.* ]]; then
    local hostrole="master"
  elif [[ "${hostname}" =~ .*register.* ]]; then
    local hostrole="register"
  else
    local hostrole="other"
  fi
  
  # 返回主机角色名字
  echo "${hostrole}"
}

# 项目配置属性格式化输出信息
project_conf_print_msg(){
  # 接收参数
  local seq_num="$1"
  local attr_key="$2"
  local attr_value="$3"

  # 格式化输出
  printf "|   %-2d   |  %-15s|  %-12s| %-25s |\n" "${seq_num}" "${attr_key}" "${attr_value}" "${array_remark[$seq_num-1]}"
}

project_conf_print_header(){
  echo "                   k8s集群部署基础属性信息列表"
  echo "-------------------------------------------------------------------"
  printf "| %7s |  %-15s| %-13s |   %-23s   |\n" "序列号" "功能条目" "  功能属性  " "       备注"
  echo "-------------------------------------------------------------------"
}

project_conf_print_tail()(
  echo "-------------------------------------------------------------------"
  echo "注意：目前脚本项目功能,支持下列选项: "
  echo "      集群模式：仅支持单主集群    容器引擎：仅支持docker类型"
  echo "      仓库协议：仅支持http类型    网络方案：仅支持flannel|calico类型"
  echo "      网络模式：仅支持iptables类型 "
)

project_conf_print_body(){
  # 接收参数
  local seq_num="$1"
  local attr_context="$2"
  local attr_value="$3"
 
  # 格式化输出具体的属性配置信息
  project_conf_print_msg "${seq_num}" "${attr_context}" "${attr_value}"
}

# 项目主机清单格式化输出信息
project_hosts_print_header(){
  echo "                k8s集群部署主机列表信息列表"
  echo "------------------------------------------------------------"
  printf "| %7s |  %-15s| %-13s |  %-10s  |\n" "序列号" "主机地址" "      短主机名      " "主机角色"
  echo "------------------------------------------------------------"
}

project_hosts_print_msg(){
  # 接收参数
  local seq_num="$1"
  local ip_addr="$2"
  local host_name="$3"
  local host_role=$(get_hosts_role "${host_name}")

  # 格式化输出
  printf "|   %-2d   |  %-11s|  %-20s| %-10s |\n" "${seq_num}" "${ip_addr}" "${host_name}" "${host_role}"
}

# 打印主机列表清单
project_hosts_print_body(){
  # 接收参数
  local seq_num="$1"
  local ip_addr="$2"
  local host_name="$3"
  
  # 格式化输出主机清单列表信息
  project_hosts_print_msg "${seq_num}" "${ip_addr}" "${host_name}"
}

project_hosts_print_tail()(
  echo "------------------------------------------------------------"
  echo "提示: 目前脚本项目暂不支持自动修改主机列表其他内容"
  echo "      如需修改，请直接编辑hosts文件"
)


# 修改具体属性值
edit_project_config_one_attr(){
  # 接收参数
  local attr_context="${array_context[$1-1]}"
  local attr_key="${array_key[$1-1]}"

  read -p "请输入您要修改的 ${attr_context} 属性值: " attr_value_new
  array_edit[${attr_key}]=${attr_value_new}
}

# 格式化输出基础属性配置信息函数
auto_print_project_conf_msg(){
  # 输出格式化表头信息
  project_conf_print_header

  # 输出格式化内容信息
  for i in $(seq ${#array_context[@]});do
    value=$(get_config_attr_value "${array_key[$i-1]}" "${config_file}")
    project_conf_print_body "${i}" "${array_context[$i-1]}" "${value}"
  done

  # 输出格式化表尾信息
  project_conf_print_tail
}

# 格式化输出修改后基础属性配置信息函数
auto_print_project_conf_edit_msg(){
  # 输出格式化表头信息
  project_conf_print_header
  
  # 输出格式化内容信息
  for i in $(seq ${#array_context[@]});do
    project_conf_print_body "${i}" "${array_context[$i-1]}" "${array_edit[${array_key[$i-1]}]}"
  done

  # 输出格式化表尾信息
  project_conf_print_tail
}


# 格式化输出属性修改后主机清单列表信息函数 
auto_print_project_hosts_msg(){
  # 获取网段信息
  target_net=$(get_config_attr_value "target_net" "${target_config_file}")
  
  # 定制主机清单序列号初始值
  let seq_num=1

  # 输出格式化表头信息
  project_hosts_print_header
  
  # 输出格式化内容信息
  for ip in $(grep "${target_net}" "${target_hosts_file}" | awk '{print $1}');do
    local host_name=$(grep $ip "${target_hosts_file}" | awk '{print $2}')
    project_hosts_print_body "${seq_num}" "${ip}" "${host_name}"
    let seq_num+=1
  done
  
  # 输出格式化表尾信息
  project_hosts_print_tail
}

# 生成配置文集函数
project_create_conf_file(){
  # 基于角色进行配置文件的同步
  if [ "${user_role}" == "develop" ]; then
    cp "${target_config_file}" "${local_config_file}"
    cp "${target_hosts_file}" "${local_hosts_file}"
  else
    # 生成配置文件
    cp "${local_config_file}" "${target_config_file}"
    cp "${local_hosts_file}" "${target_hosts_file}"
  fi
}

# 保存属性配置信息
edit_project_after_save_file(){
  # 1 修改属性信息
  for key in ${!array_edit[@]}; do
    value="${array_edit[${key}]}"
    sed -i "/^${key}=/s@${key}=.*@${key}=\"${value}\"@" "${config_file}"
  done

  # 3 修改hosts文件的网段信息
  old_target_net=$(get_config_attr_value "target_net" "${old_config_file}")
  target_net=$(get_config_attr_value "target_net" "${config_file}")
  if [ "${old_target_net}" != "${target_net}" ]; then
    sed -i "s@${old_target_net}@${target_net}@g" "${_hosts_file}"
  fi

  # 2 同步配置文件
  project_create_conf_file
}

# 调整conf相关的属性信息函数
edit_project_config_attr(){
  #
  auto_print_project_conf_msg
  while true;do
    read -p "请输入您要修改的属性ID(0表示退出): " attr_id
    input_status=$(user_input_datatype_confirm "${attr_id}")
    if [ "${input_status}" != "is_num" ]; then
      echo "请输入有效的ID"
    elif [ "${input_status}" == "is_num" ]; then
      if [ "${attr_id}" == "0" ]; then
        read -p "请输入是否按照当前修改内容进行保存(yes|no): " is_save
        [ -e ${is_save} ] && is_save="no"
        [[ "${is_save}" != "yes" && "${is_save}" != "no" ]] && is_save="no"
        if [ "${is_save}" == "yes" ];then
           edit_project_after_save_file
        elif [ "${is_save}" == "no" ];then
           project_create_conf_file          
        fi
        break
      elif [ "${attr_id}" -gt "${#array_context[@]}" ];then
        echo "请输入有效的ID"
      else
        edit_project_config_one_attr "${attr_id}"
        auto_print_project_conf_edit_msg
      fi
    fi
  done
}

# 一键自动调整配置函数
one_key_edit_project_config(){
  print::msg "all" "warning" "开始执行自动调整项目属性信息操作..."
  edit_project_config_attr
  print::msg "all" "success" "执行自动调整项目属性信息操作成功..."
  print::msg "console" "warning" "属性修改后的主机清单信息如下:"
  auto_print_project_hosts_msg
}
